package org.example.component;


import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

import java.util.Arrays;

@Component
@Aspect //申明当前类为AOP切面类  <aop:aspect ref="txManager">
public class TransactionManagerHandler {
    /**
     * 切入点配置
     */
    @Pointcut("execution(* org.example.service..*.*(..))") // <aop:pointcut id="pt" expression="execution(* org.example.service..*.*(..))"/>
    public void pointcut(){}

    /**
     * @Before 前置通知 ，切入点直接写对对应的方法名称
     */
//   @Before("pointcut()") //等价于：<aop:before method="begin" pointcut-ref="pt"/>
    public void begin(JoinPoint joinPoint) {
        Object target = joinPoint.getTarget();//被代理的对象，真实对象
        System.out.println("target = " + target);
        Object[] args = joinPoint.getArgs();
        System.out.println("args = " + Arrays.toString(args));
        System.out.println("开启事务");
    }

    /**
     * @AfterReturning 后置通知
     */
//    @AfterReturning("pointcut()") //等价于：<aop:after-returning method="commit" pointcut-ref="pt"/>
    public void commit() {
        System.out.println("提交事务");
    }
//    @AfterThrowing(pointcut = "pointcut()",throwing = "ex") //等价于：<aop:after-throwing method="rollback" pointcut-ref="pt" throwing="e"/>
    public void rollback(Throwable ex) {
        ex.printStackTrace();
        System.out.println("回滚事务");
    }
//    @After("pointcut()") //等价于 <aop:after method="close" pointcut-ref="pt"/>
    public void close() {
        System.out.println("关闭session");
    }
    //============================环绕通知/增强/advice===============================


    /**
     * @param joinPoint 环绕通知的连接点，环绕通知，需要开发者手动增强，并执行方法
     * @throws Throwable
     */
    @Around("pointcut()")
    public void allInOne(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("===================TransactionManagerHandler.allInOne=======================");

        try {
            begin(joinPoint);

            //执行连接点方法
            joinPoint.proceed();

            commit();
        } catch (Throwable e) {
            rollback(e);
            throw new RuntimeException(e);
        } finally {
            close();
        }
    }

}